package com.swan.core.utils.collection;


import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;

/**
 * @author zongf
 * @since 2022-11-26
 **/
public class ListUtil {

    /** 转换为非null数组
     * @param clz 数组中元素类型，这个参数无法省略
     * @return 数组, 不会返回 null    <br/>
     * 1. list 为空(null或者size==0)时，返回空的数组，而非null <br/>
     * 2. 正常返回 T 类型的数组，顺序和 List 中顺序保持一致 <br/>
     */
    public static <T> T[] toArray(List<T> list, Class<T> clz) {
        if (list == null || list.isEmpty()) {
            return (T[]) Array.newInstance(clz, 0);
        }
        T[] array = (T[]) Array.newInstance(clz, list.size());
        for (int i = 0; i < list.size(); i++) {
            array[i] = list.get(i);
        }
        return array;
    }

    /** 将List转换数组，可以修改类型，或对数组中元素进行增强处理 <br/>
     * @param list 列表
     * @param clz 目标数组类型
     * @param converter 类型 T 转换为 R 的方法
     * @param <T> 列表中数据类型
     * @param <R> 转换后数组的类型
     * @return R 的数组，不会返回 null  <br/>
     * 1. list 为空(null或者size==0)时，返回 R类型的空数组，而非null <br/>
     * 2. 正常返回 R 类型的数组，R 和 T 的类型可以相同 <br/>
     */
    public static <T, R> R[] toArray(List<T> list, Class<R> clz, Function<T, R> converter) {
        if (list == null || list.isEmpty()) {
            return (R[]) Array.newInstance(clz, 0);
        }

        R[] array = (R[]) Array.newInstance(clz, list.size());
        for (int i = 0; i < list.size(); i++) {
            T item = list.get(i);
            if (item == null) {
                array[i] = null;
            }else {
                array[i] = converter.apply(item);
            }
        }
        return array;
    }

    /** 按某个属性去重
     * @param list
     * @param distinctKeyGetter 去重按键
     * @return 非空List
     * @param <T>
     * @param <R>
     */
    public static <T, R> List<T> distinct(List<T> list, Function<T, R> distinctKeyGetter) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        Set<R> hashSet = new HashSet<>();
        return list.stream()
                .filter(item -> item != null)
                .filter(item ->{
                    R r = distinctKeyGetter.apply(item);
                    if (r == null) {
                        return false;
                    }
                    if (hashSet.contains(r)) {
                        return false;
                    }else {
                        hashSet.add(r);
                        return true;
                    }
                })
                .toList();
    }

    /** 提取对象的属性组成列表
     * @param list 列表
     * @param function 类型 T 转换为 R 的方法
     * @param <T> 列表中数据类型
     * @param <R> 字段列表，当为空时返回空list，不会返回null
     * @return R 类型数组，非 null
     */
    public static <T, R> List<R> toList(List<T> list, Function<T, R>  function) {
        return toList(list, function, false,  null);
    }

    /** 提取对象的属性组成列表，返回去重列表
     * @param list 列表
     * @param function 类型 T 转换为 R 的方法
     * @param <T> 列表中数据类型
     * @param <R> 字段列表，当为空时返回空list，不会返回null
     * @return R 类型数组，非 null
     */
    public static <T, R> List<R> toDistinctList(List<T> list, Function<T, R>  function) {
        return toList(list, function, true,  null);
    }

    /** 提取对象的属性组成列表，升序、不去重列表
     * @param list 列表
     * @param function 类型 T 转换为 R 的方法
     * @param <T> 列表中数据类型
     * @param <R> 字段列表，当为空时返回空list，不会返回null
     * @return R 类型数组，非 null
     */
    public static <T, R extends Comparable<R>> List<R > toAscList(List<T> list, Function<T, R>  function) {
        return toList(list, function, false, R::compareTo);
    }

    /** 提取对象的属性组成列表，去重、降序列表
     * @param list 列表
     * @param function 类型 T 转换为 R 的方法
     * @param <T> 列表中数据类型
     * @param <R> 字段列表，当为空时返回空list，不会返回null
     * @return R 类型数组，非 null
     */
    public static <T, R extends Comparable<R>> List<R> toDescList(List<T> list, Function<T, R>  function) {
        return toList(list, function, false, (o1, o2) -> -1 * o1.compareTo(o2));
    }

    /** 提取对象的属性组成列表，去重、升序
     * @param list 列表
     * @param function 类型 T 转换为 R 的方法
     * @param <T> 列表中数据类型
     * @param <R> 字段列表，当为空时返回空list，不会返回null
     * @return R 类型数组，非 null
     */
    public static <T, R extends Comparable> List<R> toDistinctAscList(List<T> list, Function<T, R>  function) {
        return toList(list, function, true,  R::compareTo);
    }

    /** 提取对象的属性组成列表，升序列表
     * @param list 列表
     * @param function 类型 T 转换为 R 的方法
     * @param <T> 列表中数据类型
     * @param <R> 字段列表，当为空时返回空list，不会返回null
     * @return R 类型数组，非 null
     */
    public static <T, R extends Comparable> List<R> toDistinctDescList(List<T> list, Function<T,  R>  function) {
        return toList(list, function, true, (o1, o2) -> -1 * o1.compareTo(o2));
    }

    /** 自动过来 null 元素
     * @param list
     * @param function 转换方法
     * @param isDistinct 是否去重
     * @param comparator 自定义排序方式
     * @param <T> 原list中的元素类型
     * @param <R> 转换后的元素类型
     * @return List<R> 不会返回 null    <br/>
     * 1. list 为null 或者 size ==0 时，返回空列表，不会返回 null <br/>
     * 2. 可以通过参数指定排序、去重等策略
     */
    public static <T, R> List<R> toList(List<T> list, Function< T,  R>  function, boolean isDistinct, Comparator<R> comparator) {
        if (list == null) {
            return Collections.emptyList();
        }
        Stream<R> stream = list.stream()
                .filter(item -> item != null)
                .map(function);
        if(isDistinct) {
            stream = stream.distinct();
        }
        if (comparator != null) {
            stream = stream.sorted(comparator);
        }
        return stream.toList();
    }

    /** 对list中的元素进行分组
     * @param list 列表
     * @param function 获取分组key的方法
     * @param <K> 分组 key
     * @param <V> list元素类型
     * @return LinkedHashMap<K, List<V>>
     */
    public static <K, V> Map<K, List<V>> groupToMap(List<V> list, Function<V, K> function) {
        if (list == null) {
            return new LinkedHashMap<>();
        }
        Map<K, List<V>> map = new LinkedHashMap<>();
        for (V item : list) {
            List<V> values = map.computeIfAbsent(function.apply(item), lst -> new ArrayList());
            values.add(item);
        }
        return map;
    }


    /** 对list中的元素转换为map,
     * @param list 列表
     * @param groupKeyGetter 获取key的方法，需要保证 key 唯一，否则会进行覆盖
     * @param groupValueGetter 获取value的方法
     * @param <K> key 类型
     * @param <V> list元素类型
     * @return LinkedHashMap<K, List<V>>
     */
    public static <K, V, E> Map<K, V> groupToMap(List<E> list, Function<E, K> groupKeyGetter, Function<E, V> groupValueGetter) {
        if (list == null) {
            return new LinkedHashMap<>();
        }
        Map<K, V> map = new HashMap<>();
        for (E item : list) {
            map.put(groupKeyGetter.apply(item), groupValueGetter.apply(item));
        }
        return map;
    }

    public static <T> List<T> subtract (List<T> list1, List<T> list2) {
        if (list1 == null) {
            return Collections.emptyList();
        }
        if (list2 == null) {
            return list1;
        }
        return list1.stream().filter(item -> !list2.contains(item)).toList();
    }

}
